package miniSchedule;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.LockSupport;

public class ScheduleService {
    Trigger trigger = new Trigger();
    ExecutorService executorService = Executors.newFixedThreadPool(6);
    private final AtomicLong sequence = new AtomicLong(); // 用于生成 Job ID

    Job schedule(Runnable task, long delay) {
        long startTime = System.currentTimeMillis() + delay;
        Job job = new Job(sequence.incrementAndGet(), task, startTime, delay, true); // 假设都是周期性的

        trigger.queue.offer(job);
        trigger.wakeUp();
        return job;
    }

    // 新增一个方法，用于从队列中移除任务
    public boolean cancel(Job job) {
        job.cancel(); // 设置取消状态并尝试中断
        // 从队列中移除，防止未来的执行
        return trigger.queue.remove(job);
    }

    // 添加关闭方法
    public void shutdown() {
        trigger.thread.interrupt();
        executorService.shutdownNow();
    }

    class Trigger {
        /**
         * 阻塞优先队列，方便获取最先执行任务
         */
        PriorityBlockingQueue<Job> queue = new PriorityBlockingQueue<>();

        Thread thread = new Thread(() -> {
            while (true) {
                while (queue.isEmpty()) {
                    LockSupport.park();
                }
                Job latelyJob  = queue.peek();
                if (latelyJob.isCancelled()) continue;

                if (latelyJob.getStartTime() <= System.currentTimeMillis()) { // 到达执行时间
                    latelyJob = queue.poll();
                    if (latelyJob.isCancelled()) continue; // 在休眠后再次检查，可能在 sleep 期间被取消
                    // 提交任务，注意我们提交的是 Job 对象本身，因为它实现了 Runnable
                    executorService.submit(latelyJob);
                    // 如果是周期性任务，创建下一个周期的任务
                    if (latelyJob.isPeriodic() && !latelyJob.isCancelled()) {
                        long nextStartTime = System.currentTimeMillis() + latelyJob.getDelay();
                        Job nextJob = new Job(latelyJob.getId(), latelyJob.getOriginalTask(), nextStartTime, latelyJob.getDelay(), true);
                        queue.offer(nextJob);
                    }
                }
                else {
                    LockSupport.parkUntil(latelyJob.getStartTime());
                }
            }
        });

        {
            thread.start();
            System.out.println("触发器启动了!");
        }

        void wakeUp() {
            LockSupport.unpark(thread);
        }
    }
}
